import { createServer } from 'http';
import { WebSocketServer } from 'ws';
import { readFile, stat } from 'fs/promises';
import { join, dirname, extname, isAbsolute } from 'path';
import open from 'open';
var __dirname = dirname(process.argv[1]);

(function (args) {
    if (args.length <= 1) return help();
    const params = {
        "port": null,
        "html_root": null,
        "ext_js": null,
        "open_browser": undefined,
    };
    initParams(); // 初始化参数

    const PORT = params.port || 15167;   // 配置服务器端口
    const STATIC_DIR = params.html_root ? getStaticDir(params.html_root) : null; // 静态文件根目录

    let connected_count = 0;         // 连接计数
    const CONNECTION_TIMEOUT = 1500; // 连接空闲超时时间
    let shutdownTimer;
    let onWsMessage = () => 0;

    initWsMessageCB(params.ext_js);
    // 创建 HTTP 服务器
    const server = createServer(params.html_root ? getServerCB : getServerCB2);
    // 创建 WebSocket 服务器
    const wss = new WebSocketServer({ server });
    initWSS(wss);

    // 启动服务器
    server.listen(PORT, () => {
        waitClosed(5000);
        if (params.open_browser)
            open(`http://127.0.0.1:${PORT}`).catch(err => console.error("无法自动打开浏览器，请手动访问:\nhttp://127.0.0.1:" + PORT));
        else console.log(`服务器已启动，请访问：http://127.0.0.1:${PORT}`);
    });


    function initParams() {
        for (let i = 0; i < args.length; i++) {
            const key = getParamKey(args[i]);
            if (key) {
                params[key] = args[++i];
            }
        }
        params.open_browser = (params.open_browser === undefined || params.open_browser === 't') && params.html_root;
    }

    function getParamKey(arg) {
        switch (arg) {
            case '-w': return 'html_root';
            case '-p': return 'port';
            case '-e': return 'ext_js';
            case '-ob': return 'open_browser';
        }
        return false;
    }

    function getStaticDir(path) {
        if (isAbsolute(path)) return path;
        return join(__dirname, path);
    }
    async function initWsMessageCB(ext_js) {
        if (!ext_js) return;
        try {
            if (!isAbsolute(ext_js)) {
                ext_js = join(__dirname, ext_js);
            }
            await stat(ext_js);
            ext_js = "file:///" + ext_js;
            const ext_script = await import(ext_js);
            onWsMessage = ext_script.onWsMessage;
        } catch (error) {
            // console.log(error);
        }
    }

    function getServerCB2(req, res) {
        // 设置响应头，允许跨域请求
        // res.setHeader('Access-Control-Allow-Origin', '*');
        // res.setHeader('Access-Control-Allow-Methods', 'GET, POST');
        // res.setHeader('Access-Control-Allow-Headers', 'Content-Type');

        // 解析URL和查询参数
        // const parsedUrl = url.parse(req.url, true);
        // const path = parsedUrl.pathname;
        // const queryParams = parsedUrl.query;

        if (req.method != 'POST') return;
        let body = "";
        req.on('data', (chunk) => {
            body += chunk.toString();
        });
        req.on('end', () => {
            // console.log(body);
            const lines = body.split('\n'); // 按行分割
            lines.forEach((line, index) => console.log(line));
        });
    }

    async function getServerCB(req, res) {
        try {
            if (!STATIC_DIR) return;
            // 构建请求的文件路径
            let filePath;
            let ws_script = '';
            if (req.url === '/') {
                filePath = join(STATIC_DIR, 'index.html');
                // 入口处添加脚本
                ws_script = getWSJS(PORT);
            } else {
                filePath = join(STATIC_DIR, req.url);
            }

            // 安全检查：防止路径遍历攻击
            if (!filePath.startsWith(STATIC_DIR)) return res.writeHead(403).end('Forbidden');

            // 检查文件是否存在
            const fileStat = await stat(filePath);

            // 如果是目录，尝试默认文件
            if (fileStat.isDirectory()) {
                filePath = join(filePath, 'index.html');
                await stat(filePath); // 再次检查文件是否存在, stat在没找到文件时会直接抛出异常，因此不用判断
            }

            // 获取文件扩展名并确定 MIME 类型
            const ext = extname(filePath).toLowerCase();
            const contentType = getMimeType(ext);

            // 读取文件内容并返回
            const fileContent = await readFile(filePath);
            res.writeHead(200, { 'Content-Type': contentType });
            res.end(ws_script + fileContent);

        } catch (err) {
            // 处理错误
            if (err.code === 'ENOENT') {
                res.writeHead(404).end('File not found');
            } else {
                console.error('Server error:', err);
                res.writeHead(500).end('Internal server error');
            }
        }
    }

    function initWSS(wss) {
        // 监听 WebSocket 连接
        wss.on('connection', (ws) => {
            connected_count++;
            onWsMessage('connection', (msg) => ws.send(msg));
            ws.on('close', () => {
                connected_count--;
                if (connected_count <= 0) {
                    waitClosed(ws);
                }
            });

            // 错误处理
            ws.on('error', console.error);
            ws.on('message', function (val) {
                const message = Buffer.from(val).toString('utf8');
                onWsMessage(message, (msg) => ws.send(msg));
            })
        });
    }
    function waitClosed(time_out) {
        time_out = time_out || CONNECTION_TIMEOUT;
        if (shutdownTimer) {
            clearTimeout(shutdownTimer);
            shutdownTimer = null;
        }
        shutdownTimer = setTimeout(() => {
            if (connected_count <= 0) {
                server.closeAllConnections();
                server.close();
            }
        }, time_out);

    }
    /** 输出帮助文本 */
    function help() {
        console.log(`
  帮助：
    -w [文件夹路径]   html根目录，index.html为入口
    -p [端口号]       端口号
    -e [具体路径]     扩展脚本。在脚本实现 [export function onWsMessage(msg, cb)] 可以接收并通信，
    -ob [t|f]        启动后是否自动打开浏览器，默认t(打开),f(不打开)
`);
    }
    // MIME 类型映射
    const MIME_TYPES = {
        '.html': 'text/html',
        '.js': 'text/javascript',
        '.css': 'text/css',
        '.json': 'application/json',
        '.png': 'image/png',
        '.jpg': 'image/jpg',
        '.gif': 'image/gif',
        '.svg': 'image/svg+xml',
        '.wav': 'audio/wav',
        '.mp3': 'audio/mp3',
        '.woff': 'font/woff',
        '.woff2': 'font/woff2',
        '.ttf': 'font/ttf',
        '.eot': 'font/eot'
    };
    function getMimeType(ext) {
        return MIME_TYPES[ext] || 'application/octet-stream';
    }

    function getWSJS(prot) {
        return `<script>
    const ws = new WebSocket("ws://127.0.0.1:${prot}");
    ws.onopen = () => {
        /* 连接成功 */
    };
    ws.onclose = () => {
        /* 连接断开 */
    };
    ws.onerror = (error) => {
        /* 错误 */
        console.log("出现错误", error);
    };
    ws.onmessage = (event) => {
        wsOnMsg(event.data);
    };
    /** 重写该方法以处理消息*/
    var wsOnMsg = console.log;
    /** 发送消息 */
    function wsSend(msg){
        ws.send(msg);
    }
</script>
`;
    }

})(process.argv.splice(2));